package com.example.shardingjdbc.config;

import com.google.common.collect.Lists;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.driver.api.ShardingSphereDataSourceFactory;
import org.apache.shardingsphere.infra.config.RuleConfiguration;
import org.apache.shardingsphere.infra.config.algorithm.ShardingSphereAlgorithmConfiguration;
import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;
import org.apache.shardingsphere.sharding.api.config.strategy.keygen.KeyGenerateStrategyConfiguration;
import org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @Package: com.example.shardingjdbc.config
 * @Author: HanWL
 * @CreateTime: 2023-05-19 15:33
 * @Version: 1.0
 **/
@Configuration
@Slf4j
public class ShardingJDBCConfig {

    @Bean
    @Primary
    public DataSource dataSource(DatasourceProperties datasourceProperties) throws SQLException {
        //数据源Map
        HikariDataSource masterDs = new HikariDataSource();
        masterDs.setDriverClassName(datasourceProperties.getDriverClassName());
        masterDs.setJdbcUrl(datasourceProperties.getUrl());
        masterDs.setUsername(datasourceProperties.getUserName());
        masterDs.setPassword(datasourceProperties.getPassword());
        Map<String, DataSource> dsMap = new HashMap<>();
        dsMap.put("db_name", masterDs);

        //配置分片规则
        List<RuleConfiguration> ruleConfigs = Lists.newArrayList();
        ruleConfigs.add(getUserRuleConfig());
        // 可选参数
        Properties prop = new Properties();
        // 打印sql
        prop.setProperty("sql-show", "true");

        return ShardingSphereDataSourceFactory.createDataSource(dsMap, ruleConfigs, prop);
    }

    /**
     * 分表配置
     */
    private ShardingRuleConfiguration getUserRuleConfig() {
        ShardingRuleConfiguration shardJdbcConfig = new ShardingRuleConfiguration();
        //把逻辑表和真实表的对应关系添加到分片规则配置中
        shardJdbcConfig.getTables().add(getTableRule01());
        //设置表的分片规则（数据的垂直拆分） 根据create_time分表
        shardJdbcConfig.setDefaultTableShardingStrategy(new StandardShardingStrategyConfiguration
                ("create_time", "date_table"));
        //设置分表策略
        Properties props = new Properties();
        shardJdbcConfig.getShardingAlgorithms().put("date_table", new ShardingSphereAlgorithmConfiguration("DatePreciseShardingAlgorithm", props));
        //设置主键生成策略
        // * 雪花算法
        Properties idProperties = new Properties();
        shardJdbcConfig.getKeyGenerators().put("snowflake", new ShardingSphereAlgorithmConfiguration("SNOWFLAKE", idProperties));

        return shardJdbcConfig;
    }

    private ShardingTableRuleConfiguration getTableRule01() {
        ShardingTableRuleConfiguration result = new ShardingTableRuleConfiguration("jy", "db_name.jy_${20230101..20991230}");
        result.setKeyGenerateStrategy(new KeyGenerateStrategyConfiguration("id", "snowflake"));

        return result;
    }
}
